home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume23 / mlpd < prev    next >
Encoding:
Internet Message Format  |  1991-01-08  |  51.0 KB

  1. Subject:  v23i076:  Feed multiple printers from one BSD lpr queue
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 6dc6d13d 1ce5265b f8c0866b 0b0db86c
  5.  
  6. Submitted-by: matt robinson <yakker@ucrmath.ucr.edu>
  7. Posting-number: Volume 23, Issue 76
  8. Archive-name: mlpd
  9.  
  10. [ I have not tested this as I don't run LDP.  --r$ ]
  11.  
  12. This program (MLPD) is a little piece of code I wrote to use a single
  13. printer queue for a set of multiple printers.  It's kind of wierd to
  14. set up, but once it is running, it should help out a lot.
  15.  
  16. The program runs under a Sun OS environment.  It has been tried out
  17. under 4.1 SunOS, and I had it tried out under a 4.3 BSD environment,
  18. thanks to the help of nash@ucselx.sdsu.edu (Thanks, Ron!) I hope that 
  19. it works for you.  Please send me all bug reports, special things that
  20. would make your life easier, etc., so on, so forth.  If you do have any
  21. questions at all, please mail me to let me know about what you need.
  22.  
  23. #! /bin/sh
  24. # This is a shell archive.  Remove anything before this line, then feed it
  25. # into a shell via "sh file" or similar.  To overwrite existing files,
  26. # type "sh file -c".
  27. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  28. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  29. # Contents:  COPYRIGHT Makefile README config.h daemon.c lock.c mlp.c
  30. #   mlpd.8 pfile.c printcap.c printer.c
  31. # Wrapped by rsalz@litchi.bbn.com on Wed Dec  5 12:24:56 1990
  32. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  33. echo If this archive is complete, you will see the following message:
  34. echo '          "shar: End of archive."'
  35. if test -f 'COPYRIGHT' -a "${1}" != "-c" ; then 
  36.   echo shar: Will not clobber existing file \"'COPYRIGHT'\"
  37. else
  38.   echo shar: Extracting \"'COPYRIGHT'\" \(1054 characters\)
  39.   sed "s/^X//" >'COPYRIGHT' <<'END_OF_FILE'
  40. X/*
  41. X * Copyright (c) 1990 Regents of the University of California.
  42. X * All rights reserved.
  43. X *
  44. X * Redistribution and use in source and binary forms are permitted
  45. X * provided that the above copyright notice and this paragraph are
  46. X * duplicated in all such forms and that any documentation,
  47. X * advertising materials, and other materials related to such
  48. X * distribution and use acknowledge that the software was developed
  49. X * by the University of California, Riverside. 
  50. X *
  51. X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
  52. X *        Irvine.  Riverside.  Ri - ver - side.
  53. X *
  54. X * The name of the University may not be used to endorse or promote 
  55. X * products derived from this software without specific prior written
  56. X * permission.
  57. X *
  58. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  59. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  60. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  61. X * 
  62. X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
  63. X * SCCS keywords: @(#)COPYRIGHT    1.3 12/1/90
  64. X */
  65. X
  66. END_OF_FILE
  67.   if test 1054 -ne `wc -c <'COPYRIGHT'`; then
  68.     echo shar: \"'COPYRIGHT'\" unpacked with wrong size!
  69.   fi
  70.   # end of 'COPYRIGHT'
  71. fi
  72. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  73.   echo shar: Will not clobber existing file \"'Makefile'\"
  74. else
  75.   echo shar: Extracting \"'Makefile'\" \(1775 characters\)
  76.   sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  77. X#
  78. X# Copyright (c) 1990 Regents of the University of California.
  79. X# All rights reserved.
  80. X#
  81. X# Redistribution and use in source and binary forms are permitted
  82. X# provided that the above copyright notice and this paragraph are
  83. X# duplicated in all such forms and that any documentation,
  84. X# advertising materials, and other materials related to such
  85. X# distribution and use acknowledge that the software was developed
  86. X# by the University of California, Riverside. 
  87. X#
  88. X# NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
  89. X#        Irvine.  Riverside.  Ri - ver - side.
  90. X#
  91. X# The name of the University may not be used to endorse or promote 
  92. X# products derived from this software without specific prior written
  93. X# permission.
  94. X#
  95. X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  96. X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  97. X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  98. X# 
  99. X# MLPD -- Multiple Line Printer Daemon (Version 1.3)
  100. X# SCCS keywords: @(#)Makefile    1.3 12/1/90
  101. X#
  102. X
  103. X#
  104. X# Note : Make sure to look in config.h for other parameters.
  105. X#
  106. X
  107. X# Include this line if you are running under the Sun OS environment.
  108. X# It is designed basically to change from using <sys/dir.h> to using
  109. X# <dirent.h>, because of the System V compatibility.
  110. X#
  111. X# The debug flag is also specified because of some people's desire to
  112. X# take a small peek at what is going on.  You can use it, but it is
  113. X# very noisy, and shouldn't be used when running normally.
  114. X#
  115. XEXTRA_FLAGS  = -DSUN #-DDEBUG -g
  116. X#
  117. X# And now, the rest of the story.
  118. X#
  119. XOBJS         =  daemon.o lock.o pfile.o mlp.o printcap.o printer.o
  120. XPROG         =  mlpd
  121. XCC           =  cc
  122. XCFLAGS       =  -c $(EXTRA_FLAGS)
  123. X
  124. X$(PROG) : $(OBJS)
  125. X    $(CC) -o $(PROG) $(OBJS)
  126. X
  127. Xclean    :
  128. X    /bin/rm -f *.o $(PROG)
  129. END_OF_FILE
  130.   if test 1775 -ne `wc -c <'Makefile'`; then
  131.     echo shar: \"'Makefile'\" unpacked with wrong size!
  132.   fi
  133.   # end of 'Makefile'
  134. fi
  135. if test -f 'README' -a "${1}" != "-c" ; then 
  136.   echo shar: Will not clobber existing file \"'README'\"
  137. else
  138.   echo shar: Extracting \"'README'\" \(4085 characters\)
  139.   sed "s/^X//" >'README' <<'END_OF_FILE'
  140. X/*
  141. X * Copyright (c) 1990 Regents of the University of California.
  142. X * All rights reserved.
  143. X *
  144. X * Redistribution and use in source and binary forms are permitted
  145. X * provided that the above copyright notice and this paragraph are
  146. X * duplicated in all such forms and that any documentation,
  147. X * advertising materials, and other materials related to such
  148. X * distribution and use acknowledge that the software was developed
  149. X * by the University of California, Riverside. 
  150. X *
  151. X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
  152. X *        Irvine.  Riverside.  Ri - ver - side.
  153. X *
  154. X * The name of the University may not be used to endorse or promote 
  155. X * products derived from this software without specific prior written
  156. X * permission.
  157. X *
  158. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  159. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  160. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  161. X * 
  162. X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
  163. X * SCCS keywords: @(#)README    1.3 12/1/90
  164. X */
  165. X
  166. XNOTE:  This program is in its first testing stages.  If I send it out,
  167. X       and people like it, I'll post it to the USENET network.  If
  168. X       not, I'll just put it on a resume.  This is the first version,
  169. X       and I have already started working on a new version that has
  170. X       many more features, all that remain very simplistic to the
  171. X       user, which is my main objective.
  172. X
  173. X
  174. XNow on with the real important stuff:
  175. X
  176. X
  177. XThis program (MLPD) is a little piece of code I wrote to use a single
  178. Xprinter queue for a set of multiple printers.  It's kind of wierd to
  179. Xset up, but once it is running, it should help out a lot.
  180. X
  181. XHere are the steps for a clean configuration, in proper order :
  182. X---------------------------------------------------------------
  183. X
  184. X1.  Edit Makefile to your particular system and needs.  If you are running
  185. X    under a SunOS environment, you need to define -DSUN, and if you want
  186. X    to print out hari-kari debug messages, you need to specify -DDEBUG.
  187. X
  188. X2.  Compile the program, or get it operational. (Whichever comes first.)
  189. X
  190. X3.  Turn off the printing to the base printer that your employees, friends,
  191. X    or students print to, and turn off queueing on the other printers.  For
  192. X    example, 'lp' is your base printer (Where most people type in 'lpr'),
  193. X    and your other printers are the real printers that will be doing the
  194. X    actual printing (like 'lp1', 'lp2', etc.)
  195. X
  196. X4.  Make sure all of the printers are properly set up in the /etc/printcap
  197. X    so that the printers can run smoothly.  Make sure that your main
  198. X    printer ('lp' is your main printer, from #3.) doesn't do any printing
  199. X    and that your other printers area actually connected to the devices.
  200. X
  201. X5.  Try it out!  The command to start off the program is :
  202. X
  203. X    mlpd -p [<base printer> <printer1> <printer2> ...] [-t <timeout>]
  204. X
  205. X    For example, a command line following #3 and #4 would be:
  206. X
  207. X    mlpd -p lp lp1 lp2 -t 5
  208. X
  209. X    In this example, the main queueing printer is lp, the other printers
  210. X    are lp1 and lp2, and the timeout to check for a print job is 5 seconds.
  211. X6.  If it works, try to set it up in your rc.local to start up when you 
  212. X    start up your system.  Make sure, however, that you put the mlpd entry
  213. X    after starting up lpd.  Otherwise, mlpd will not function.
  214. X
  215. XThe program runs under a Sun OS environment.  It has been tried out
  216. Xunder 4.1 SunOS, and I had it tried out under a 4.3 BSD environment,
  217. Xthanks to the help of nash@ucselx.sdsu.edu (Thanks, Ron!) I hope that 
  218. Xit works for you.  Please send me all bug reports, special things that
  219. Xwould make your life easier, etc., so on, so forth.  If you do have any
  220. Xquestions at all, please mail me to let me know about what you need.
  221. XI'll be out with a manual page soon enough.  (Gotta learn a bit about
  222. Xnroff...Too much TeX and LaTeX.)
  223. X
  224. X--Matt
  225. X
  226. X____________________________________________________________________________
  227. XMatt D. Robinson                            Internet: yakker@ucrmath.ucr.edu
  228. XSystems Programming Group, UC Riverside         UUCP: ..!ucsd!ucrmath!yakker
  229. END_OF_FILE
  230.   if test 4085 -ne `wc -c <'README'`; then
  231.     echo shar: \"'README'\" unpacked with wrong size!
  232.   fi
  233.   # end of 'README'
  234. fi
  235. if test -f 'config.h' -a "${1}" != "-c" ; then 
  236.   echo shar: Will not clobber existing file \"'config.h'\"
  237. else
  238.   echo shar: Extracting \"'config.h'\" \(1824 characters\)
  239.   sed "s/^X//" >'config.h' <<'END_OF_FILE'
  240. X/*
  241. X * Copyright (c) 1990 Regents of the University of California.
  242. X * All rights reserved.
  243. X *
  244. X * Redistribution and use in source and binary forms are permitted
  245. X * provided that the above copyright notice and this paragraph are
  246. X * duplicated in all such forms and that any documentation,
  247. X * advertising materials, and other materials related to such
  248. X * distribution and use acknowledge that the software was developed
  249. X * by the University of California, Riverside. 
  250. X *
  251. X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
  252. X *        Irvine.  Riverside.  Ri - ver - side.
  253. X *
  254. X * The name of the University may not be used to endorse or promote 
  255. X * products derived from this software without specific prior written
  256. X * permission.
  257. X *
  258. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  259. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  260. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  261. X * 
  262. X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
  263. X * SCCS keywords: @(#)config.h    1.3 12/1/90
  264. X */
  265. X
  266. X#include <sys/types.h>
  267. X#include <sys/socket.h>
  268. X#include <sys/un.h>
  269. X#include <sys/param.h>
  270. X#include <sys/ioctl.h>
  271. X#include <sys/time.h>
  272. X#include <sys/wait.h>
  273. X#include <sys/stat.h>
  274. X#include <syslog.h>
  275. X#include <time.h>
  276. X#ifdef SUN
  277. X#include <dirent.h>
  278. X#else
  279. X#include <sys/dir.h>
  280. X#endif
  281. X#include <stdio.h>
  282. X#include <ctype.h>
  283. X#include <errno.h>
  284. X
  285. X#define TRUE                 1
  286. X#define FALSE                0
  287. X#ifdef DEBUG
  288. X#define debug(x) fprintf(stderr, "%s", (x))
  289. X#else
  290. X#define debug(x) fprintf(stderr, "%s", "")
  291. X#endif
  292. X
  293. Xtypedef struct 
  294. X{
  295. X    char *name[512];
  296. X    char *directory[512];
  297. X} printerstruct;
  298. X
  299. Xextern char *LP_SPOOL_DIRECTORY;
  300. Xextern int  TIMEOUT;
  301. X
  302. Xint init_daemon();
  303. Xint lock_printer();
  304. Xint bomb();
  305. Xint check_prs();
  306. Xint check_base_printer();
  307. Xvoid exit();
  308. Xchar *malloc();
  309. END_OF_FILE
  310.   if test 1824 -ne `wc -c <'config.h'`; then
  311.     echo shar: \"'config.h'\" unpacked with wrong size!
  312.   fi
  313.   # end of 'config.h'
  314. fi
  315. if test -f 'daemon.c' -a "${1}" != "-c" ; then 
  316.   echo shar: Will not clobber existing file \"'daemon.c'\"
  317. else
  318.   echo shar: Extracting \"'daemon.c'\" \(3479 characters\)
  319.   sed "s/^X//" >'daemon.c' <<'END_OF_FILE'
  320. X/*
  321. X * Copyright (c) 1990 Regents of the University of California.
  322. X * All rights reserved.
  323. X *
  324. X * Redistribution and use in source and binary forms are permitted
  325. X * provided that the above copyright notice and this paragraph are
  326. X * duplicated in all such forms and that any documentation,
  327. X * advertising materials, and other materials related to such
  328. X * distribution and use acknowledge that the software was developed
  329. X * by the University of California, Riverside. 
  330. X *
  331. X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
  332. X *        Irvine.  Riverside.  Ri - ver - side.
  333. X *
  334. X * The name of the University may not be used to endorse or promote 
  335. X * products derived from this software without specific prior written
  336. X * permission.
  337. X *
  338. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  339. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  340. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  341. X * 
  342. X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
  343. X * SCCS keywords: @(#)daemon.c    1.3 12/1/90
  344. X */
  345. X
  346. X#include "config.h"
  347. X
  348. X/*
  349. X// (int) init_daemon() -- Initialize a process as a daemon process.
  350. X//
  351. X// This function will start off by forking a process off from the
  352. X// parent, and give control over to the child by opening up the
  353. X// root directory, duplicating stdout and stderr for the child,
  354. X// and release the terminal control for the main terminal.
  355. X// The program also calls lock_printer() after the fork(), so that
  356. X// the child process is saved into a file when the status of the 
  357. X// program needs to be checked.
  358. X//
  359. X// Arguments : None
  360. X*/
  361. Xint init_daemon(base)
  362. Xchar *base;
  363. X{
  364. X    int pid;
  365. X
  366. X    /*
  367. X    // Fork off a process.
  368. X    */
  369. X    if ((pid = fork()) < 0)
  370. X    {
  371. X        bomb("fork");
  372. X    }
  373. X    /*
  374. X    // First we will check in on the parent, and get rid of it.
  375. X    */
  376. X    if (pid)
  377. X    {
  378. X        exit(0);
  379. X    }
  380. X    /*
  381. X    // Now we specifically want all of the code in the child.
  382. X    // We try to lock down the printer daemon by creating a lock
  383. X    // file.
  384. X    */
  385. X    if (lock_printer(base) < 0)
  386. X    {
  387. X        bomb("lock_printer");
  388. X    }
  389. X    /*
  390. X    // Well, if this returns, then we must start closing off the
  391. X    // terminal control.  We call open(), then dup2() for stdout
  392. X    // and stderr, then we try to call setpgrp on the process to
  393. X    // put itself into the background.  Only the ioctl call will
  394. X    // release control from the terminal.  Then we close the de-
  395. X    // scriptor created by the second open() call.
  396. X    */
  397. X    if (open("/", 0) < 0) { bomb("open"); }
  398. X    if (dup2(0, 1) < 0) { bomb("dup2:stdout"); }
  399. X    if (dup2(0, 2) < 0) { bomb("dup2:stderr"); }
  400. X    if (setpgrp(0, getpid()) < 0) { bomb("setpgrp"); }
  401. X    /*
  402. X    // Well, everything must have worked correctly, so we will default
  403. X    // back to the parent.
  404. X    */
  405. X}
  406. X
  407. X/*
  408. X// (int) bomb() -- Display an error message, then exit.
  409. X//
  410. X// bomb() simply will call perror() and send the function call a string
  411. X// declaring the error to be displayed to the user.  Once this returns
  412. X// we can then call exit().
  413. X//
  414. X// Arguments : char *str (The string message to be displayed)
  415. X*/
  416. Xint bomb(str)
  417. Xchar *str;
  418. X{
  419. X    char buf[1024];
  420. X    time_t now;
  421. X    struct tm *nowtime;
  422. X
  423. X
  424. X    buf[0] = '\0';
  425. X    (void)perror(str);
  426. X    now = (time_t)time();
  427. X    nowtime = localtime(&now);
  428. X    (void)sprintf(buf, "Date: (%d/%d/%d)\n\
  429. X        Time: (%d:%d:%d)\n\
  430. X        Message: Process died from error message (%s)\n\n", 
  431. X        nowtime->tm_mon, nowtime->tm_mday, nowtime->tm_year, 
  432. X        nowtime->tm_hour, nowtime->tm_min, nowtime->tm_sec, 
  433. X        str);
  434. X    (void)openlog("mlpd", LOG_PID, LOG_LPR);
  435. X    (void)syslog(LOG_ERR, buf);
  436. X    (void)closelog();
  437. X    (void)exit(1);
  438. X}
  439. END_OF_FILE
  440.   if test 3479 -ne `wc -c <'daemon.c'`; then
  441.     echo shar: \"'daemon.c'\" unpacked with wrong size!
  442.   fi
  443.   # end of 'daemon.c'
  444. fi
  445. if test -f 'lock.c' -a "${1}" != "-c" ; then 
  446.   echo shar: Will not clobber existing file \"'lock.c'\"
  447. else
  448.   echo shar: Extracting \"'lock.c'\" \(3637 characters\)
  449.   sed "s/^X//" >'lock.c' <<'END_OF_FILE'
  450. X/*
  451. X * Copyright (c) 1990 Regents of the University of California.
  452. X * All rights reserved.
  453. X *
  454. X * Redistribution and use in source and binary forms are permitted
  455. X * provided that the above copyright notice and this paragraph are
  456. X * duplicated in all such forms and that any documentation,
  457. X * advertising materials, and other materials related to such
  458. X * distribution and use acknowledge that the software was developed
  459. X * by the University of California, Riverside. 
  460. X *
  461. X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
  462. X *        Irvine.  Riverside.  Ri - ver - side.
  463. X *
  464. X * The name of the University may not be used to endorse or promote 
  465. X * products derived from this software without specific prior written
  466. X * permission.
  467. X *
  468. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  469. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  470. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  471. X * 
  472. X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
  473. X * SCCS keywords: @(#)lock.c    1.3 12/1/90
  474. X */
  475. X
  476. X#include "config.h"
  477. X
  478. X/*
  479. X// lock_printer() -- Lock up the printer daemon for once per machine.
  480. X// 
  481. X// The lock_printer() process will try to save the pid of the process
  482. X// that is about to run to a file, to reference later when we need to
  483. X// check to see if the program is running (We do not want to let the
  484. X// program run more than once per machine.)
  485. X//
  486. X// Arguments : None
  487. X*/
  488. Xint lock_printer(base)
  489. Xchar *base;
  490. X{
  491. X    FILE *fp, *fopen();
  492. X    void exit();
  493. X    char buf[1024];
  494. X    int pid;
  495. X
  496. X    /*
  497. X    // First we will try to fopen() the file.  If we can't get
  498. X    // the file open, we have to assume that either the file has
  499. X    // been moved, or the program has been recompiled and there
  500. X    // is a new lock file directory.  If we can fopen() it,
  501. X    // we will run through this [if..then] loop and handle the
  502. X    // conditions.
  503. X    */
  504. X    buf[0] = '\0';
  505. X    (void)sprintf(buf, "/etc/mlpd.%s.pid", base);
  506. X    if ((fp = fopen(buf, "r")) != NULL)
  507. X    {
  508. X        /*
  509. X        // Try to read the number from the file.
  510. X        */
  511. X        if (fscanf(fp, "%d", &pid) < 0)
  512. X        {
  513. X            perror("lock_printer:fscanf:fopen");
  514. X            exit(-1);
  515. X        }
  516. X        /*
  517. X        // If we can read the number, then we need to see whether
  518. X        // the process still exists.  If it does, then we want to
  519. X        // Just exit out, and tell the user that the program is 
  520. X        // still running; otherwise, we need to clean up the file
  521. X        // that exists in the directory, and create the file showing
  522. X        // the new PID in the file.
  523. X        */
  524. X        if (getpgrp(pid) >= 0)
  525. X        {
  526. X            if (fprintf(stderr, "This program is already running \
  527. X                    (PID# : %d)\n", pid) < 0)
  528. X            {
  529. X                bomb("lock_printer");
  530. X            }
  531. X            exit(1);
  532. X        }
  533. X    }
  534. X    /*
  535. X    // If we got to this point in the code, then either there wasn't a
  536. X    // lock file in the directory, or the process which was running
  537. X    // died off.  In either case, remove the file that we found, if
  538. X    // there.
  539. X    */
  540. X    if (unlink(buf) < 0)
  541. X    {
  542. X        /* 
  543. X        // Do nothing.  We want to try to remove the 
  544. X        // file no matter what.
  545. X        */
  546. X    }
  547. X    /*
  548. X    // Now we want to try and fopen the file for writing.  This is
  549. X    // to place the present getpid() into the file for reference
  550. X    // later.
  551. X    */
  552. X    if ((fp = fopen(buf, "w")) == NULL)
  553. X    {
  554. X        bomb("lock_printer:/etc/mlpd.pid:fopen");
  555. X    }
  556. X    /*
  557. X    // Try to fprintf() the getpid() return value into the file.
  558. X    */
  559. X    if (fprintf(fp, "%d", getpid()) < 0)
  560. X    {
  561. X        bomb("lock_printer:fprintf");
  562. X    }
  563. X    /*
  564. X    // If we get here, all we have to do is close the file, and
  565. X    // go back to the init_daemon() process.
  566. X    */
  567. X    if (fclose(fp) < 0)
  568. X    {
  569. X        bomb("lock_printer:fclose");
  570. X    }
  571. X    /*
  572. X    // Well, everything must have worked, so we'll just head back and
  573. X    // tell the calling program that everything is okay.
  574. X    */
  575. X    return 1;
  576. X}
  577. END_OF_FILE
  578.   if test 3637 -ne `wc -c <'lock.c'`; then
  579.     echo shar: \"'lock.c'\" unpacked with wrong size!
  580.   fi
  581.   # end of 'lock.c'
  582. fi
  583. if test -f 'mlp.c' -a "${1}" != "-c" ; then 
  584.   echo shar: Will not clobber existing file \"'mlp.c'\"
  585. else
  586.   echo shar: Extracting \"'mlp.c'\" \(4126 characters\)
  587.   sed "s/^X//" >'mlp.c' <<'END_OF_FILE'
  588. X/*
  589. X * Copyright (c) 1990 Regents of the University of California.
  590. X * All rights reserved.
  591. X *
  592. X * Redistribution and use in source and binary forms are permitted
  593. X * provided that the above copyright notice and this paragraph are
  594. X * duplicated in all such forms and that any documentation,
  595. X * advertising materials, and other materials related to such
  596. X * distribution and use acknowledge that the software was developed
  597. X * by the University of California, Riverside. 
  598. X *
  599. X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
  600. X *        Irvine.  Riverside.  Ri - ver - side.
  601. X *
  602. X * The name of the University may not be used to endorse or promote 
  603. X * products derived from this software without specific prior written
  604. X * permission.
  605. X *
  606. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  607. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  608. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  609. X * 
  610. X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
  611. X * SCCS keywords: @(#)mlp.c    1.3 12/1/90
  612. X */
  613. X
  614. X#include "config.h"
  615. Xchar *LP_SPOOL_DIRECTORY;
  616. Xint  TIMEOUT;
  617. Xint  errno;
  618. X
  619. X/*
  620. X// main() -- The main program.
  621. X//
  622. X// This will start off looking to create the printer structure,
  623. X// initialize the process so that it is running as a daemon,
  624. X// find the total number of printers to check, and start up a
  625. X// select/test loop that looks for print jobs in the main queue
  626. X// and moves/prints the new files in new queues.
  627. X//
  628. X// Arguments : None
  629. X*/
  630. Xint main(argc, argv)
  631. Xint argc;
  632. Xchar *argv[];
  633. X{
  634. X    int count, clt, nready, pready, no_of_printers;
  635. X    struct timeval timeout;
  636. X    printerstruct *printers;
  637. X#ifndef lint
  638. X    FILE *myfp, *fopen();
  639. X#endif
  640. X    int fprintf();
  641. X    int write();
  642. X    void exit();
  643. X
  644. X    /* 
  645. X    // First, initialize the printer structure.
  646. X    */
  647. X#ifdef lint
  648. X    printers = NULL;
  649. X#else
  650. X    printers = (printerstruct *) malloc(sizeof(printerstruct));
  651. X#endif
  652. X    /*
  653. X    // Next, parse through all of the arguments to find information
  654. X    // that we need, and set all variables necessary.
  655. X    */
  656. X    no_of_printers = parse_arguments(argc, argv, printers);
  657. X    /* 
  658. X    // Set the timeout values for the select process to be 2 seconds,
  659. X    // which keeps the CPU usage down.
  660. X    */
  661. X    timeout.tv_sec = 2;
  662. X    timeout.tv_usec = 0;
  663. X    count = 0;
  664. X    while(TRUE)
  665. X    {
  666. X        /*
  667. X        // Do a select() for about 2 seconds on nothing, so that
  668. X        // all we do is a time wait without causing a lot of CPU
  669. X        // usage.  I'm hoping that this isn't too much bother for
  670. X        // the users.  
  671. X        */
  672. X        if (count == 0)
  673. X        {
  674. X            (void)restart_all_printers(no_of_printers, printers);
  675. X            /* 
  676. X            // (15 * 2 seconds) + 2 seconds;
  677. X            */
  678. X            count = 16;            
  679. X        }
  680. X        --count;
  681. X        if ((nready = select((int) 0, (fd_set *) NULL, (fd_set *) NULL, 
  682. X            (fd_set *) NULL, (struct timeval *) &timeout)) < 0)
  683. X        {
  684. X            if (errno != EINTR)
  685. X            {
  686. X                bomb("select");
  687. X            }
  688. X            else
  689. X            {
  690. X                nready = 0;
  691. X            }
  692. X        }
  693. X        /*
  694. X        // Well, from here, we want to go through the printers
  695. X        // to make sure we either don't have anything to print,
  696. X        // or all of the printers are busy.  We check the base
  697. X        // printer (Which ever one that is), and see if it has
  698. X        // any files to print.  If it does, then we want to print
  699. X        // out the file to one of the other printers, if any
  700. X        // of them are available.
  701. X        */
  702. X        pready = 0;
  703. X        while ((nready == 0) && 
  704. X            (check_base_printer() > 0) &&
  705. X            (pready == 0))
  706. X        {
  707. X            debug("Found a file to print.\n");
  708. X            /*
  709. X            // Begin to check through the list of printers
  710. X            // and see if we have one free.  If we do, print
  711. X            // to that printer, otherwise, skip it.  We do 
  712. X            // NOT want to queue files on printers...We want
  713. X            // to maintain one queue.  (See README).
  714. X            */
  715. X            for (clt = 0; clt < no_of_printers; ++clt)
  716. X            {
  717. X                /*
  718. X                // This checks to see if the printer is
  719. X                // available to print on.
  720. X                */
  721. X                if ((pready = check_prs(printers, clt)) < 0)
  722. X                {
  723. X                    bomb("check_prs");
  724. X                }
  725. X                else if (pready == 0)
  726. X                {
  727. X                    debug("I can print out a file.\n");
  728. X                    /*
  729. X                    // If we get here, we can print
  730. X                    // out a file on this printer.
  731. X                    */
  732. X                    if (print_file(printers, clt) < 0)
  733. X                    {
  734. X                        bomb("print_file");
  735. X                    }
  736. X                    clt = no_of_printers;
  737. X                }
  738. X            }
  739. X        }
  740. X    }
  741. X}
  742. END_OF_FILE
  743.   if test 4126 -ne `wc -c <'mlp.c'`; then
  744.     echo shar: \"'mlp.c'\" unpacked with wrong size!
  745.   fi
  746.   # end of 'mlp.c'
  747. fi
  748. if test -f 'mlpd.8' -a "${1}" != "-c" ; then 
  749.   echo shar: Will not clobber existing file \"'mlpd.8'\"
  750. else
  751.   echo shar: Extracting \"'mlpd.8'\" \(3786 characters\)
  752.   sed "s/^X//" >'mlpd.8' <<'END_OF_FILE'
  753. X.\" Copyright (c) 1983 Regents of the University of California.
  754. X.\" All rights reserved.  The Berkeley software License Agreement
  755. X.\" specifies the terms and conditions for redistribution.
  756. X.\"
  757. X.\" @(#)mlpd.8 1.3 12/1/90; from UCR SunOS 4.1
  758. X.\"
  759. X.TH MLPD 8 "8 November 1990"
  760. X.SH NAME
  761. Xmlpd \- multiple line printer daemon
  762. X.SH SYNOPSIS
  763. X
  764. X.B mlpd 
  765. X[
  766. X.B \-p <base pr> <pr1> <pr2> ...
  767. X] [
  768. X.B \-t <timeout>
  769. X]
  770. X.SH DESCRIPTION
  771. X
  772. X.LP
  773. X.B mlpd 
  774. Xis a multiple line printer daemon, which is set up in your
  775. Xrc.local (read the manual on rc (8)) script, which will monitor files
  776. Xbeing printed on your system.  mlpd will look in the base printer
  777. Xdirectory for files, try to find jobs that need to be printed, and
  778. Xtake those jobs and move them to any available printers.  Printer jobs
  779. Xno longer have to wait for a larger job in front of them.  This allows
  780. Xfor optimization in printing files to any number of printers.
  781. X
  782. X.SH OPTIONS
  783. X
  784. X.LP
  785. X.SS \-p <base pr> <pr1> <pr2> ...
  786. X
  787. X.LP
  788. XSpecifies the printers to print on.  For example, if lp is the 
  789. Xnormal line printer to queue to, and the real printers are connected
  790. Xlp1 and lp2, then I would specify
  791. X.B \-p lp lp1 lp2
  792. Xas my print options.  The super-user can specify any number of printers 
  793. Xfrom the command line.  The program will look up these printers in 
  794. X/etc/printcap entry to verify their existance, and use their 
  795. Xspooling directories as the directories to queue in.  If the printers 
  796. Xare not in /etc/printcap, or the proper spooling directories do not 
  797. Xexist, then the program will exit and log all information to syslog().
  798. X.LP
  799. X.SS \-t <timeout>
  800. X
  801. X.LP
  802. XSpecifies the amount of time to wait before checking the base printer
  803. Xqueue.  Normally this time is set to 2 seconds, but the user can specify
  804. Xwhat they wish.  It is normally suggested to let the default remain intact,
  805. Xas the program will run better under this environment.
  806. X.SH OPERATION
  807. X.SS Operation/Syntax of Program
  808. X.LP
  809. XThe program runs by first trying to check all of the command line arguments,
  810. Xand setting all of the proper printing options.  Once it knows where each
  811. Xprinter queueing directory is, it then goes out and starts into a loop,
  812. Xwhere is calls select() for a period of seconds equal to that specified on
  813. Xthe command line, or a default of 2 seconds.  After the timeout has occurred,
  814. Xthe daemon will go out and look for jobs in the base printer queue.  If
  815. Xit finds any jobs, it will then check to see if any of the printers specified
  816. Xare available for printing.  If one of the printers is free to print, it
  817. Xwill send that printer the print job first available.  It will continue to
  818. Xdo this until either there are no more jobs in the printer queue, or all 
  819. Xof the printers are busy.  Every 30 seconds, the printers are restarted
  820. Xagain, in case any printer files become jammed for some reason.  Should
  821. Xthe super-user want to kill off the program, there will be a lock file in
  822. X/etc with the name "mlpd.<base pr>.pid", which will contain the PID of 
  823. Xthe daemon running.
  824. X
  825. X.SH "SEE ALSO"
  826. X.BR lpq (1),
  827. X.BR lpr (1),
  828. X.BR lprm (1),
  829. X.BR hosts (5),
  830. X.BR hosts.equiv (5),
  831. X.BR printcap (5),
  832. X.BR lpc (8),
  833. X.BR pac (8)
  834. X.SH BUGS
  835. X
  836. XThe program can only allow for 512 printers.  If you can edit the code,
  837. Xyou can raise this amount, but I really didn't imagine someone trying
  838. Xto watch over more than 512 printers.
  839. X
  840. XIf you start up mlpd before starting up lpd in rc.local, the program 
  841. Xwill exit, because it was not able to connect to the lpd device.
  842. X
  843. XThe timeout value is set to 2 seconds, so if this begins to slow your
  844. Xsystem down, increase this value.  I would not suggest lowering it.
  845. X
  846. XIf you find something else wrong with it, please let me know.  I'm ever
  847. Xwilling to fix anything wrong with it, add new functionality, and so forth.
  848. XContact yakker@ucrmath.ucr.edu for any other information, bug reports, etc.
  849. END_OF_FILE
  850.   if test 3786 -ne `wc -c <'mlpd.8'`; then
  851.     echo shar: \"'mlpd.8'\" unpacked with wrong size!
  852.   fi
  853.   # end of 'mlpd.8'
  854. fi
  855. if test -f 'pfile.c' -a "${1}" != "-c" ; then 
  856.   echo shar: Will not clobber existing file \"'pfile.c'\"
  857. else
  858.   echo shar: Extracting \"'pfile.c'\" \(4610 characters\)
  859.   sed "s/^X//" >'pfile.c' <<'END_OF_FILE'
  860. X/*
  861. X * Copyright (c) 1990 Regents of the University of California.
  862. X * All rights reserved.
  863. X *
  864. X * Redistribution and use in source and binary forms are permitted
  865. X * provided that the above copyright notice and this paragraph are
  866. X * duplicated in all such forms and that any documentation,
  867. X * advertising materials, and other materials related to such
  868. X * distribution and use acknowledge that the software was developed
  869. X * by the University of California, Riverside. 
  870. X *
  871. X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
  872. X *        Irvine.  Riverside.  Ri - ver - side.
  873. X *
  874. X * The name of the University may not be used to endorse or promote 
  875. X * products derived from this software without specific prior written
  876. X * permission.
  877. X *
  878. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  879. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  880. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  881. X * 
  882. X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
  883. X * SCCS keywords: @(#)pfile.c    1.3 12/1/90
  884. X */
  885. X
  886. X#include "config.h"
  887. Xextern char *LP_SPOOL_DIRECTORY; 
  888. Xextern int TIMEOUT;
  889. X
  890. X/*
  891. X// parse_arguments() -- Get printer information from argv.
  892. X//
  893. X// This function when called will return a structure containing
  894. X// the printers and their respective spooling directories in
  895. X// a structure.  
  896. X//
  897. X// Arguments : printerstruct *printers (The printer structure)
  898. X*/
  899. Xint parse_arguments(argc, argv, printers)
  900. Xint argc;
  901. Xchar *argv[];
  902. Xprinterstruct *printers;
  903. X{
  904. X    int i, origargc;
  905. X    int no_of_printers, ncnt, can_exit;
  906. X    char base[1024];
  907. X    
  908. X    can_exit = FALSE;
  909. X    i = 0;
  910. X    origargc = argc;
  911. X    if (argc < 5)
  912. X    {
  913. X        usage(argv[0], "Not enough arguments.\n");
  914. X    }
  915. X    while (--argc)
  916. X    {
  917. X        if (!strcmp("-t", argv[i]))
  918. X        {
  919. X            if ((atoi(argv[i+1])) && (i+1 != argc))
  920. X            {
  921. X                TIMEOUT = atoi(argv[i + 1]);
  922. X            }
  923. X            else
  924. X            {
  925. X                usage(argv[0], "Bad timeout value.\n");
  926. X            }
  927. X        }
  928. X        if (!strcmp("-p", argv[i]))
  929. X        {
  930. X            can_exit = TRUE;
  931. X            no_of_printers = 0;
  932. X            for (ncnt = i + 1; ncnt < origargc; ++ncnt)
  933. X            {
  934. X                if (!strcmp(argv[ncnt], "-t"))
  935. X                {
  936. X                    ncnt = origargc;
  937. X                }
  938. X                else if (ncnt == i + 1)
  939. X                {
  940. X                    (void)strcpy(base, argv[ncnt]);
  941. X                    find_pr(argv[ncnt]);
  942. X                }
  943. X                else
  944. X                {
  945. X                    add_pr(printers, argv[ncnt],
  946. X                        no_of_printers);
  947. X                    ++no_of_printers;
  948. X                }
  949. X            }
  950. X            if (no_of_printers < 2)
  951. X            {
  952. X                usage(argv[0], "Less than 2 printers specified.\n");
  953. X            }
  954. X        }
  955. X        ++i;
  956. X    }
  957. X    if (!TIMEOUT) TIMEOUT = 2;
  958. X    if (can_exit == FALSE)
  959. X    {
  960. X        usage(argv[0], "Bad arguments used.  Must use -p option.\n");
  961. X    }
  962. X    init_daemon(base);
  963. X    return(no_of_printers);
  964. X}
  965. X
  966. Xusage(arg, str)
  967. Xchar *arg, *str;
  968. X{
  969. X    (void)fprintf(stderr, "%sUsage : %s [-p <main printer> <pr1> <pr2> ...] [-t <timeout>]\n", str, arg);
  970. X    exit(1);
  971. X}
  972. X
  973. X/* 
  974. X// add_pr() - add a printer to the list of printers.
  975. X// 
  976. X// Arguments :  printerstruct *printers -- the printer structure.
  977. X//        char *str -- the name of the printer specified on command line.
  978. X//              int nop -- the number of the printer item;
  979. X*/
  980. Xint add_pr(printers, str, nop)
  981. Xprinterstruct *printers;
  982. Xchar *str;
  983. Xint nop;
  984. X{
  985. X    char line[BUFSIZ];
  986. X    char *tmpbuf;
  987. X    int status;
  988. X    char *bp;
  989. X
  990. X#ifndef lint
  991. X    printers->directory[nop] = (char *) malloc(512);
  992. X    printers->name[nop] = (char *) malloc(512);
  993. X    tmpbuf = (char *)malloc(BUFSIZ);
  994. X    bp = (char *)malloc(BUFSIZ/2);
  995. X#else
  996. X    printers->directory[nop] = NULL;
  997. X    printers->name[nop] = NULL;
  998. X    tmpbuf = NULL;
  999. X    bp = NULL;
  1000. X#endif
  1001. X    if ((status = pgetent(line, str)) < 0)
  1002. X    {
  1003. X        bomb("pgetent");
  1004. X    }
  1005. X    if (status == 0)
  1006. X    {
  1007. X        (void)fprintf(stderr, "No such printer (%s) exists on this system.\n", str);
  1008. X        exit(1);
  1009. X    }
  1010. X    if ((tmpbuf = (char *)pgetstr((char *)"sd", (char *)&bp)) == NULL)
  1011. X    {
  1012. X        bomb("get_prdir_from_printcap:pgetstr");
  1013. X    }
  1014. X    (void)strcpy((char *)printers->directory[nop], (char *)tmpbuf);
  1015. X    (void)strcpy((char *)printers->name[nop], (char *)str);
  1016. X}
  1017. X
  1018. X/* 
  1019. X// find_pr() - find the base printer in the printcap file.
  1020. X// 
  1021. X// This function will set the LP_SPOOL_DIRECTORY to the base printer
  1022. X// spooling directory specified in /etc/printcap.
  1023. X//
  1024. X// Arguments : char *str -- the name of the printer specified on command line.
  1025. X*/
  1026. X
  1027. Xfind_pr(str)
  1028. Xchar *str;
  1029. X{
  1030. X    char line[BUFSIZ];
  1031. X#ifndef lint
  1032. X    char *newdir;
  1033. X    char *bp;
  1034. X#endif
  1035. X    int status;
  1036. X
  1037. X#ifndef lint
  1038. X    newdir = (char *)malloc(BUFSIZ);
  1039. X    bp = (char *)malloc(BUFSIZ/2);
  1040. X#endif
  1041. X    if ((status = pgetent(line, str)) < 0)
  1042. X    {
  1043. X        bomb("pgetent");
  1044. X    }
  1045. X    if (status == 0)
  1046. X    {
  1047. X        (void)fprintf(stderr, "No such printer (%s) exists on this system.\n", str);
  1048. X        exit(1);
  1049. X    }
  1050. X    if ((newdir = (char *)pgetstr("sd", &bp)) == NULL)
  1051. X    {
  1052. X        bomb("get_prdir_from_printcap:pgetstr");
  1053. X    }
  1054. X    LP_SPOOL_DIRECTORY = (char *)strdup(newdir);
  1055. X}
  1056. END_OF_FILE
  1057.   if test 4610 -ne `wc -c <'pfile.c'`; then
  1058.     echo shar: \"'pfile.c'\" unpacked with wrong size!
  1059.   fi
  1060.   # end of 'pfile.c'
  1061. fi
  1062. if test -f 'printcap.c' -a "${1}" != "-c" ; then 
  1063.   echo shar: Will not clobber existing file \"'printcap.c'\"
  1064. else
  1065.   echo shar: Extracting \"'printcap.c'\" \(6858 characters\)
  1066.   sed "s/^X//" >'printcap.c' <<'END_OF_FILE'
  1067. X/*
  1068. X * Copyright (c) 1983 Regents of the University of California.
  1069. X * All rights reserved.
  1070. X *
  1071. X * Redistribution and use in source and binary forms are permitted
  1072. X * provided that the above copyright notice and this paragraph are
  1073. X * duplicated in all such forms and that any documentation,
  1074. X * advertising materials, and other materials related to such
  1075. X * distribution and use acknowledge that the software was developed
  1076. X * by the University of California, Berkeley.  The name of the
  1077. X * University may not be used to endorse or promote products derived
  1078. X * from this software without specific prior written permission.
  1079. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1080. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1081. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1082. X */
  1083. X
  1084. X#ifndef lint
  1085. Xstatic char sccsid[] = "@(#)printcap.c    5.3 (Berkeley) 6/30/88";
  1086. X#endif /* not lint */
  1087. X
  1088. X#define    BUFSIZ    1024
  1089. X#define MAXHOP    32    /* max number of tc= indirections */
  1090. X
  1091. X#include <ctype.h>
  1092. X#include <stdio.h>
  1093. X/*
  1094. X * termcap - routines for dealing with the terminal capability data base
  1095. X *
  1096. X * BUG:        Should use a "last" pointer in tbuf, so that searching
  1097. X *        for capabilities alphabetically would not be a n**2/2
  1098. X *        process when large numbers of capabilities are given.
  1099. X * Note:    If we add a last pointer now we will screw up the
  1100. X *        tc capability. We really should compile termcap.
  1101. X *
  1102. X * Essentially all the work here is scanning and decoding escapes
  1103. X * in string capabilities.  We don't use stdio because the editor
  1104. X * doesn't, and because living w/o it is not hard.
  1105. X */
  1106. X
  1107. X#define PRINTCAP
  1108. X
  1109. X#ifdef PRINTCAP
  1110. X#define tgetent    pgetent
  1111. X#define tskip    pskip
  1112. X#define tgetstr    pgetstr
  1113. X#define tdecode pdecode
  1114. X#define tdecode pdecode
  1115. X#define tnchktc    pnchktc
  1116. X#define    tnamatch pnamatch
  1117. X#undef E_TERMCAP
  1118. X#define E_TERMCAP "/etc/printcap"
  1119. X#define V6
  1120. X#endif
  1121. X
  1122. Xstatic    char *tbuf;
  1123. Xstatic    int hopcount;        /* detect infinite loops in termcap, init 0 */
  1124. Xchar    *tskip();
  1125. Xchar    *tgetstr();
  1126. Xchar    *tdecode();
  1127. Xchar    *getenv();
  1128. X
  1129. X/*
  1130. X * Get an entry for terminal name in buffer bp,
  1131. X * from the termcap file.  Parse is very rudimentary;
  1132. X * we just notice escaped newlines.
  1133. X */
  1134. Xtgetent(bp, name)
  1135. X    char *bp, *name;
  1136. X{
  1137. X    register char *cp;
  1138. X    register int c;
  1139. X    register int i = 0, cnt = 0;
  1140. X    char ibuf[BUFSIZ];
  1141. X#ifndef lint
  1142. X    char *cp2;
  1143. X#endif
  1144. X    int tf;
  1145. X
  1146. X    tbuf = bp;
  1147. X    tf = 0;
  1148. X#ifndef V6
  1149. X    cp = getenv("TERMCAP");
  1150. X    /*
  1151. X     * TERMCAP can have one of two things in it. It can be the
  1152. X     * name of a file to use instead of /etc/termcap. In this
  1153. X     * case it better start with a "/". Or it can be an entry to
  1154. X     * use so we don't have to read the file. In this case it
  1155. X     * has to already have the newlines crunched out.
  1156. X     */
  1157. X    if (cp && *cp) {
  1158. X        if (*cp!='/') {
  1159. X            cp2 = getenv("TERM");
  1160. X            if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
  1161. X                (void)strcpy(bp,cp);
  1162. X                return(tnchktc());
  1163. X            } else {
  1164. X                tf = open(E_TERMCAP, 0);
  1165. X            }
  1166. X        } else
  1167. X            tf = open(cp, 0);
  1168. X    }
  1169. X    if (tf==0)
  1170. X        tf = open(E_TERMCAP, 0);
  1171. X#else
  1172. X    tf = open(E_TERMCAP, 0);
  1173. X#endif
  1174. X    if (tf < 0)
  1175. X        return (-1);
  1176. X    for (;;) {
  1177. X        cp = bp;
  1178. X        for (;;) {
  1179. X            if (i == cnt) {
  1180. X                cnt = read(tf, ibuf, BUFSIZ);
  1181. X                if (cnt <= 0) {
  1182. X                    (void)close(tf);
  1183. X                    return (0);
  1184. X                }
  1185. X                i = 0;
  1186. X            }
  1187. X            c = ibuf[i++];
  1188. X            if (c == '\n') {
  1189. X                if (cp > bp && cp[-1] == '\\'){
  1190. X                    cp--;
  1191. X                    continue;
  1192. X                }
  1193. X                break;
  1194. X            }
  1195. X            if (cp >= bp+BUFSIZ) {
  1196. X                (void)write(2,"Termcap entry too long\n", 23);
  1197. X                break;
  1198. X            } else
  1199. X                *cp++ = c;
  1200. X        }
  1201. X        *cp = 0;
  1202. X
  1203. X        /*
  1204. X         * The real work for the match.
  1205. X         */
  1206. X        if (tnamatch(name)) {
  1207. X            (void)close(tf);
  1208. X            return(tnchktc());
  1209. X        }
  1210. X    }
  1211. X}
  1212. X
  1213. X/*
  1214. X * tnchktc: check the last entry, see if it's tc=xxx. If so,
  1215. X * recursively find xxx and append that entry (minus the names)
  1216. X * to take the place of the tc=xxx entry. This allows termcap
  1217. X * entries to say "like an HP2621 but doesn't turn on the labels".
  1218. X * Note that this works because of the left to right scan.
  1219. X */
  1220. Xtnchktc()
  1221. X{
  1222. X    register char *p, *q;
  1223. X    char tcname[16];    /* name of similar terminal */
  1224. X    char tcbuf[BUFSIZ];
  1225. X    char *holdtbuf = tbuf;
  1226. X    int l;
  1227. X
  1228. X    p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  1229. X    while (*--p != ':')
  1230. X        if (p<tbuf) {
  1231. X            (void)write(2, "Bad termcap entry\n", 18);
  1232. X            return (0);
  1233. X        }
  1234. X    p++;
  1235. X    /* p now points to beginning of last field */
  1236. X    if (p[0] != 't' || p[1] != 'c')
  1237. X        return(1);
  1238. X    (void)strcpy(tcname,p+3);
  1239. X    q = tcname;
  1240. X    while (q && *q != ':')
  1241. X        q++;
  1242. X    *q = 0;
  1243. X    if (++hopcount > MAXHOP) {
  1244. X        (void)write(2, "Infinite tc= loop\n", 18);
  1245. X        return (0);
  1246. X    }
  1247. X    if (tgetent(tcbuf, tcname) != 1)
  1248. X        return(0);
  1249. X    for (q=tcbuf; *q != ':'; q++)
  1250. X        ;
  1251. X    l = p - holdtbuf + strlen(q);
  1252. X    if (l > BUFSIZ) {
  1253. X        (void)write(2, "Termcap entry too long\n", 23);
  1254. X        q[BUFSIZ - (p-tbuf)] = 0;
  1255. X    }
  1256. X    (void)strcpy(p, q+1);
  1257. X    tbuf = holdtbuf;
  1258. X    return(1);
  1259. X}
  1260. X
  1261. X/*
  1262. X * Tnamatch deals with name matching.  The first field of the termcap
  1263. X * entry is a sequence of names separated by |'s, so we compare
  1264. X * against each such name.  The normal : terminator after the last
  1265. X * name (before the first field) stops us.
  1266. X */
  1267. Xtnamatch(np)
  1268. X    char *np;
  1269. X{
  1270. X    register char *Np, *Bp;
  1271. X
  1272. X    Bp = tbuf;
  1273. X    if (*Bp == '#')
  1274. X        return(0);
  1275. X    for (;;) {
  1276. X        for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  1277. X            continue;
  1278. X        if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  1279. X            return (1);
  1280. X        while (*Bp && *Bp != ':' && *Bp != '|')
  1281. X            Bp++;
  1282. X        if (*Bp == 0 || *Bp == ':')
  1283. X            return (0);
  1284. X        Bp++;
  1285. X    }
  1286. X}
  1287. X
  1288. X/*
  1289. X * Skip to the next field.  Notice that this is very dumb, not
  1290. X * knowing about \: escapes or any such.  If necessary, :'s can be put
  1291. X * into the termcap file in octal.
  1292. X */
  1293. Xstatic char *
  1294. Xtskip(bp)
  1295. X    register char *bp;
  1296. X{
  1297. X
  1298. X    while (*bp && *bp != ':')
  1299. X        bp++;
  1300. X    if (*bp == ':')
  1301. X        bp++;
  1302. X    return (bp);
  1303. X}
  1304. X
  1305. X/*
  1306. X * Get a string valued option.
  1307. X * These are given as
  1308. X *    cl=^Z
  1309. X * Much decoding is done on the strings, and the strings are
  1310. X * placed in area, which is a ref parameter which is updated.
  1311. X * No checking on area overflow.
  1312. X */
  1313. Xchar *
  1314. Xtgetstr(id, area)
  1315. X    char *id, **area;
  1316. X{
  1317. X    register char *bp = tbuf;
  1318. X
  1319. X    for (;;) {
  1320. X        bp = tskip(bp);
  1321. X        if (!*bp)
  1322. X            return (0);
  1323. X        if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  1324. X            continue;
  1325. X        if (*bp == '@')
  1326. X            return(0);
  1327. X        if (*bp != '=')
  1328. X            continue;
  1329. X        bp++;
  1330. X        return (tdecode(bp, area));
  1331. X    }
  1332. X}
  1333. X
  1334. X/*
  1335. X * Tdecode does the grung work to decode the
  1336. X * string capability escapes.
  1337. X */
  1338. Xstatic char *
  1339. Xtdecode(str, area)
  1340. X    register char *str;
  1341. X    char **area;
  1342. X{
  1343. X    register char *cp;
  1344. X    register int c;
  1345. X    register char *dp;
  1346. X    int i;
  1347. X
  1348. X    cp = *area;
  1349. X    while ((c = *str++) && c != ':') {
  1350. X        switch (c) {
  1351. X
  1352. X        case '^':
  1353. X            c = *str++ & 037;
  1354. X            break;
  1355. X
  1356. X        case '\\':
  1357. X            dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
  1358. X            c = *str++;
  1359. Xnextc:
  1360. X            if (*dp++ == c) {
  1361. X                c = *dp++;
  1362. X                break;
  1363. X            }
  1364. X            dp++;
  1365. X            if (*dp)
  1366. X                goto nextc;
  1367. X            if (isdigit(c)) {
  1368. X                c -= '0', i = 2;
  1369. X                do
  1370. X                    c <<= 3, c |= *str++ - '0';
  1371. X                while (--i && isdigit(*str));
  1372. X            }
  1373. X            break;
  1374. X        }
  1375. X        *cp++ = c;
  1376. X    }
  1377. X    *cp++ = 0;
  1378. X    str = *area;
  1379. X    *area = cp;
  1380. X    return (str);
  1381. X}
  1382. END_OF_FILE
  1383.   if test 6858 -ne `wc -c <'printcap.c'`; then
  1384.     echo shar: \"'printcap.c'\" unpacked with wrong size!
  1385.   fi
  1386.   # end of 'printcap.c'
  1387. fi
  1388. if test -f 'printer.c' -a "${1}" != "-c" ; then 
  1389.   echo shar: Will not clobber existing file \"'printer.c'\"
  1390. else
  1391.   echo shar: Extracting \"'printer.c'\" \(9835 characters\)
  1392.   sed "s/^X//" >'printer.c' <<'END_OF_FILE'
  1393. X/*
  1394. X * Copyright (c) 1990 Regents of the University of California.
  1395. X * All rights reserved.
  1396. X *
  1397. X * Redistribution and use in source and binary forms are permitted
  1398. X * provided that the above copyright notice and this paragraph are
  1399. X * duplicated in all such forms and that any documentation,
  1400. X * advertising materials, and other materials related to such
  1401. X * distribution and use acknowledge that the software was developed
  1402. X * by the University of California, Riverside. 
  1403. X *
  1404. X * NOTE : That's Riverside.  Not Berkeley, not Santa Cruz, not even
  1405. X *        Irvine.  Riverside.  Ri - ver - side.
  1406. X *
  1407. X * The name of the University may not be used to endorse or promote 
  1408. X * products derived from this software without specific prior written
  1409. X * permission.
  1410. X *
  1411. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1412. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1413. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1414. X * 
  1415. X * MLPD -- Multiple Line Printer Daemon (Version 1.3)
  1416. X * SCCS keywords: @(#)printer.c    1.3 12/1/90
  1417. X */
  1418. X
  1419. X#include "config.h"
  1420. X
  1421. X/*
  1422. X// check_base_printer() -- Check the main printer queue.
  1423. X//
  1424. X// This function will go through the main printer queue and see
  1425. X// whether or not there are any files to print out.  If there are,
  1426. X// notify the main program the number of files to print out.  We
  1427. X// mainly want to see that there are files to print, so that all
  1428. X// of the other printer queues can be checked.
  1429. X*/
  1430. X
  1431. Xint check_base_printer()
  1432. X{
  1433. X#ifdef  SUN
  1434. X    struct dirent *d; 
  1435. X#else
  1436. X    struct direct *d;
  1437. X#endif
  1438. X    DIR *dirpointer; 
  1439. X    int nitems;
  1440. X
  1441. X    /*
  1442. X    // First we open up the spooling directory for the main
  1443. X    // spooler.  Queueing should be allowed on this printer,
  1444. X    // but printing should be turned off.  We open up the
  1445. X    // directory to read the files in them.
  1446. X    */
  1447. X    (void)debug("Checking base printer spooling directory...\n");
  1448. X    if ((dirpointer = opendir(LP_SPOOL_DIRECTORY)) == NULL)
  1449. X    {
  1450. X        debug("Couldn't open directory.\n");
  1451. X        return -1;
  1452. X    }
  1453. X    nitems = 0;
  1454. X    /*
  1455. X    // Now, while we have the chance, let's check out the files
  1456. X    // in the directory and see whether something is printing or
  1457. X    // not (if nothing is printing, there won't be any files in
  1458. X    // the directory.  lpd will delete them off.)
  1459. X    */
  1460. X    while ((d = readdir(dirpointer)) != NULL)
  1461. X    {
  1462. X        debug("Checking files in directory.\n");
  1463. X        /*
  1464. X        // See if the file has a df* extension.
  1465. X        // This is the type of file that we want to use to 
  1466. X        // print out.
  1467. X        */
  1468. X        if (!strncmp(d->d_name, "cf", 2))
  1469. X        {
  1470. X            debug("Incrementing file count.\n");
  1471. X            ++nitems;
  1472. X        }
  1473. X    }
  1474. X    /*
  1475. X    // Now close off the directory, and get back to main().
  1476. X    */
  1477. X    (void)closedir(dirpointer);
  1478. X    return (nitems);
  1479. X}
  1480. X
  1481. X/*
  1482. X// check_prs() -- Check each printer queue.
  1483. X//
  1484. X// This function will go through the each printer queue and see
  1485. X// whether or not there are any files to print out.  If there are,
  1486. X// notify the main program the printer is busy, otherwise tell the
  1487. X// main program that we would like a print job sent to us.  All of
  1488. X// the printer queues are checked through this machine.
  1489. X*/
  1490. X
  1491. Xint check_prs(printers, cnt)
  1492. Xprinterstruct *printers;
  1493. Xint cnt;
  1494. X{
  1495. X#ifdef  SUN
  1496. X    struct dirent *d; 
  1497. X#else
  1498. X    struct direct *d;
  1499. X#endif
  1500. X    DIR *dirpointer; 
  1501. X    int nitems;
  1502. X
  1503. X    /*
  1504. X    // Try and create a char[] for the directory where 
  1505. X    // the printer is located.  
  1506. X    */
  1507. X    /*
  1508. X    // First we open up the spooling directory for our new
  1509. X    // spooler.  Printing should be allowed on this printer,
  1510. X    // but queueing should be turned off.  We open up the
  1511. X    // directory to read the files in them.
  1512. X    */
  1513. X    if ((dirpointer = opendir(printers->directory[cnt])) == NULL)
  1514. X    {
  1515. X        bomb("check_prs:opendir");
  1516. X        return -1;
  1517. X    }
  1518. X    nitems = 0;
  1519. X    /*
  1520. X    // Now, while we have the chance, let's check out the files
  1521. X    // in the directory and see whether something is printing or
  1522. X    // not.  If something is printing, then we don't want to send
  1523. X    // a job to this printer.  If nothing is printing, we want
  1524. X    // to ship out a job to the printer ASAP.
  1525. X    */
  1526. X    while ((d = readdir(dirpointer)) != NULL)
  1527. X    {
  1528. X        if (!strncmp(d->d_name, "cf", 2))
  1529. X        {
  1530. X            ++nitems;
  1531. X        }
  1532. X    }
  1533. X    /*
  1534. X    // Close off the directory pointer.
  1535. X    */
  1536. X    (void)closedir(dirpointer);
  1537. X    /*
  1538. X    // Return the number of files that are printing.
  1539. X    */
  1540. X    return(nitems);
  1541. X}
  1542. X
  1543. X/*
  1544. X// print_file() -- Print out a file in the spool directory.
  1545. X//
  1546. X// First, we try to find a file in the directory where we have
  1547. X// specified that we are going to print from.  If we do, then we
  1548. X// take the job from one printer area to another, and "kick-start"
  1549. X// the new printer into printing out the jobs (We should have to
  1550. X// send a signal to lpd to get this job running.)
  1551. X*/
  1552. X
  1553. Xint print_file(p, cnt)
  1554. Xprinterstruct *p;
  1555. Xint cnt;
  1556. X{
  1557. X#ifdef  SUN
  1558. X    struct dirent *d; 
  1559. X#else
  1560. X    struct direct *d;
  1561. X#endif
  1562. X    DIR *dirpointer; 
  1563. X    int nitems;
  1564. X
  1565. X    /*
  1566. X    // Open up the spooling directory.
  1567. X    */ 
  1568. X    (void)debug("Yes, I can now print out a file!\n");
  1569. X    if ((dirpointer = opendir(LP_SPOOL_DIRECTORY)) == NULL)
  1570. X    {
  1571. X        return -1;
  1572. X    }
  1573. X    nitems = 0;
  1574. X    /*
  1575. X    // Try to find some number of files to print out on the 
  1576. X    // printer.  If we find a file, we send that file to the new
  1577. X    // directory, and send a signal to the lpd program and 
  1578. X    // return back to the main program.  If we do not get any
  1579. X    // file from the directory, something must be messed up, so
  1580. X    // we need to return our exit status to the main program.
  1581. X    // While we are at it, we should pass along the control file 
  1582. X    // that goes with the data file, so that the printer can get 
  1583. X    // the proper information for the banner page, accounting, etc.
  1584. X    */
  1585. X    while (((d = readdir(dirpointer)) != NULL) && (nitems == 0))
  1586. X    {
  1587. X        /*
  1588. X        // Check to see that the file we want to print
  1589. X        // is a data file type in the directory.
  1590. X        */
  1591. X        if (!strncmp(d->d_name, "cf", 2))
  1592. X        {
  1593. X            /*
  1594. X            // Move the files.
  1595. X            */
  1596. X            (void)debug("I am now attempting to move the files.\n");
  1597. X            move_files(d->d_name, p, cnt);
  1598. X            /*
  1599. X            // Send off the signal to the lpd program.
  1600. X            // We never use the return value, though.
  1601. X            */
  1602. X            (void)debug("Starting up the printer.\n");
  1603. X            (void)send_lpd_signal(p->name[cnt]);
  1604. X            ++nitems;
  1605. X        }
  1606. X    }
  1607. X    /*
  1608. X    // Close off the directory.
  1609. X    */
  1610. X    (void)closedir(dirpointer);
  1611. X    if (nitems == 0)
  1612. X    {
  1613. X        bomb("readdir");
  1614. X    }
  1615. X    return(0);
  1616. X}
  1617. X
  1618. X/*
  1619. X// move_files() -- move the files from one spooling directory to another.
  1620. X//
  1621. X// This function will move all of the files associated with a print job
  1622. X// to a new spooling directory.
  1623. X//
  1624. X// Arguments: char *cffile -- the name of the control file.
  1625. X//            printerstruct *p -- the printers structure.
  1626. X//            int cnt -- the index into printerstruct specifying the printer
  1627. X//                       directory to move the files to.
  1628. X*/
  1629. Xmove_files(cffile, p, cnt)
  1630. Xchar *cffile;
  1631. Xprinterstruct *p;
  1632. Xint cnt;
  1633. X{
  1634. X    char tmpbuf1[1024],tmpbuf2[1024],xbuf[1024],data[1024];
  1635. X    FILE *fp, *fopen();
  1636. X
  1637. X    xbuf[0] = '\0'; data[0] = '\0';
  1638. X    (void)sprintf(xbuf, "%s/%s", LP_SPOOL_DIRECTORY, cffile);
  1639. X    (void)debug("Opening and reading control file");
  1640. X    if ((fp = fopen(xbuf, "r")) == NULL)
  1641. X    {
  1642. X        (void)debug("Bombing on fopen().\n");
  1643. X        bomb("move_files:fopen");
  1644. X    }
  1645. X    data[0] = '\0';
  1646. X    while (fgets(data, 1024, fp) > 0)
  1647. X    {
  1648. X        if (data[0] == 'f')
  1649. X        {
  1650. X            /* 
  1651. X            // Must be a file that we want...Move it.
  1652. X            */
  1653. X            (void)debug("Moving data file.\n");
  1654. X            tmpbuf1[0] = '\0'; tmpbuf2[0] = '\0';
  1655. X            data[strlen(data)-1] = '\0';
  1656. X            (void)sprintf(tmpbuf1,"%s/%s",LP_SPOOL_DIRECTORY,&data[1]);
  1657. X            (void)sprintf(tmpbuf2,"%s/%s",p->directory[cnt],&data[1]);
  1658. X            if (rename(tmpbuf1, tmpbuf2) != 0)
  1659. X            {
  1660. X                bomb("move_files:fgets:rename");
  1661. X            }
  1662. X        }
  1663. X        data[0] = '\0';
  1664. X    }
  1665. X    (void)fclose(fp);
  1666. X    tmpbuf1[0] = '\0'; tmpbuf2[0] = '\0';
  1667. X    (void)sprintf(tmpbuf1, "%s/%s", LP_SPOOL_DIRECTORY,cffile);
  1668. X    (void)sprintf(tmpbuf2, "%s/%s", p->directory[cnt],cffile);
  1669. X    (void)debug("Moving control file.\n");
  1670. X    if (rename(tmpbuf1, tmpbuf2) != 0)
  1671. X    {
  1672. X        bomb("move_files:rename");
  1673. X    }
  1674. X}
  1675. X
  1676. X/*
  1677. X// restart_all_printers() -- send a signal to restart all printers.
  1678. X//
  1679. X// We want to restart all printers when we first start up so that we can
  1680. X// clear jobs from those queues.  This will be run every 30 seconds.
  1681. X//
  1682. X// Arguments: int nop -- The total number of printers.
  1683. X//            printerstruct *printers -- the printers structure.
  1684. X*/
  1685. X
  1686. Xint restart_all_printers(nop, printers)
  1687. Xint nop;
  1688. Xprinterstruct *printers;
  1689. X{
  1690. X    int clt;
  1691. X
  1692. X    for (clt = 0; clt < nop; ++clt)
  1693. X    {
  1694. X        (void)send_lpd_signal(printers->name[clt]);
  1695. X    }
  1696. X}
  1697. X
  1698. X/*
  1699. X// send_lpd_signal() -- Send a signal to lpd to start printing from a printer.
  1700. X//
  1701. X// This function will create a socket, try and connect using that socket to
  1702. X// the default socket for the printer, and then if a connection can be made,
  1703. X// the printer is sent a control code to print out all files for a specific
  1704. X// printer.  If this returns a \0, then everything was okay.
  1705. X//
  1706. X// Arguments : char *printer; (Name of the printer to use)
  1707. X*/
  1708. X
  1709. Xint send_lpd_signal(printer)
  1710. Xchar *printer;
  1711. X{
  1712. X    struct sockaddr_un server;
  1713. X    register int s, n;
  1714. X    char buf[1024];
  1715. X
  1716. X    s = socket(AF_UNIX, SOCK_STREAM, 0);
  1717. X    if (s < 0) 
  1718. X    {
  1719. X        if (errno == EMFILE)
  1720. X        {
  1721. X            bomb("send_lpd_signal:socket:EMFILE");
  1722. X        }
  1723. X        else if (errno == ENFILE)
  1724. X        {
  1725. X            bomb("send_lpd_signal:socket:ENFILE");
  1726. X        }
  1727. X        else if (errno == ENOBUFS)
  1728. X        {
  1729. X            bomb("send_lpd_signal:socket:ENOBUFS");
  1730. X        }
  1731. X        bomb("send_lpd_signal:socket:dont_know");
  1732. X    }
  1733. X    server.sun_family = AF_UNIX;
  1734. X#ifndef lint
  1735. X    (void)strcpy((char *)server.sun_path, (char *)"/dev/printer");
  1736. X#endif
  1737. X    if ((int)connect(s, (struct sockaddr *)&server, (int)strlen(server.sun_path) + 2) < 0) 
  1738. X    {
  1739. X        bomb("connect");
  1740. X        (void) close(s);
  1741. X        return(0);
  1742. X    }
  1743. X    (void) sprintf(buf, "\1%s\n", printer);
  1744. X    n = strlen(buf);
  1745. X    if (write(s, buf, n) != n) 
  1746. X    {
  1747. X        bomb("write");
  1748. X        (void) close(s);
  1749. X        return(0);
  1750. X    }
  1751. X    if (read(s, buf, 1) == 1) 
  1752. X    {
  1753. X        if (buf[0] == '\0') 
  1754. X        {
  1755. X            (void)close(s);
  1756. X            return(1);
  1757. X        }
  1758. X        (void)putchar(buf[0]);
  1759. X    }
  1760. X    while ((n = read(s, buf, sizeof(buf))) > 0)
  1761. X        (void)fwrite(buf, 1, n, stdout);
  1762. X    (void)close(s);
  1763. X    (void)debug("Signal has been sent to the printer %s.\n");
  1764. X    return(0);
  1765. X}
  1766. END_OF_FILE
  1767.   if test 9835 -ne `wc -c <'printer.c'`; then
  1768.     echo shar: \"'printer.c'\" unpacked with wrong size!
  1769.   fi
  1770.   # end of 'printer.c'
  1771. fi
  1772. echo shar: End of archive.
  1773. exit 0
  1774. exit 0 # Just in case...
  1775.